#! /usr/bin/python

# date: 29.12.2014
# name: Franz Profelt
# email: franz.
# description: python script for changing screenylouts and adding new screenlayouts with arandr

import os
import sys
import shutil
import argparse
import pickle

ROOTFOLDER = os.path.expanduser('~/.screen-settings/')
DATAFILENAME = '{0}dataList.pickle'.format(ROOTFOLDER)
CURRENTCONFIGFILE = '{0}currentScreenSettings.sh'.format(ROOTFOLDER)

# model class
class settingsModel:
    def __init__(self):
        self.files = []
        self.desc = []
    
    def add(self, f, d, index):
        self.files.insert(index, f)
        self.desc.insert(index, d)

    def remove(self, modenumber):
        self.files.remove(self.files[modenumber])
        self.desc.remove(self.desc[modenumber])
    
    def modes(self):
        return range(0, min(len(self.files), len(self.desc)))
    
    def printAll(self):
        print str(self)
        
    def __str__(self):
        return ''.join(["[f:'{0}' d:'{1}' m:{2}]\n".format(f,d,m) for f,d,m in zip(self.files, self.desc, self.modes())])
        
    def toHelpString(self):
        return ''.join(["\t{0} ... {1} (calls '{2}')\n".format(m,d,f) for f,d,m in zip(self.files, self.desc, self.modes())])
    
    @staticmethod
    def load_from_file(filename):
        with open(filename, 'r') as fp:
            model = pickle.load(fp)
        return model
    
    def store_to_file(self, filename):
        with open(filename, 'w') as fp:
            pickle.dump(self, fp)

# main class
class application:
    def __init__(self, verbosity):
        self.verbosity = verbosity
        
    def _p(self, msg):
        # check verbosity
        if self.verbosity:
            print msg

    def add_layout(self, filename, description, modenumber, callFlag):
        self._p('add new screen layout called')
        
        # check call flag
        if callFlag:
            self._p('call arandr')
            os.system('arandr')
        
        self._p('add layout to internal model')
        # add layout to model
        self.model.add(filename, description, modenumber)
        
        self._p('store new model to file')
        # store model to file
        self.model.store_to_file(DATAFILENAME)
    
    def remove_layout(self, modenumber, deleteFlag):
        self._p('remove layout called')
        
        # check flag
        if deleteFlag:
            self._p('delete configuration file')
            os.remove('{0}{1}'.format(ROOTFOLDER,self.model.files[modenumber]))
        
        self._p('remove layout from model')
        self.model.remove(modenumber)
        
        self._p('store new model to file')
        # store model to file
        self.model.store_to_file(DATAFILENAME)

    def apply_layout(self, modenumber):
        self._p('apply layout called')
        
        # check valid modenumber
        if modenumber in self.model.modes():
            self._p('copy configuration and replace current configuration')
            shutil.copy('{0}{1}'.format(ROOTFOLDER, self.model.files[modenumber]), CURRENTCONFIGFILE)
            self._p('call the configuration file')
            os.system('bash {0}'.format(CURRENTCONFIGFILE))
        else:
            print 'ERROR: invalid layout mode'
    
    def apply_current(self):
        self._p('apply current called')
        self._p('check if current config file exists')
        if os.path.isfile(CURRENTCONFIGFILE):
            self._p('apply current config')
            os.system('bash {0}'.format(CURRENTCONFIGFILE))
        else:
            self._p('no current config file exists')
        
        
    def main(self):
        self._p('started')
        
        # check if data file exists
        self._p('check if data file exists')
        if os.path.isfile(DATAFILENAME):
            # get available modes from saved file
            self._p('read model from saved file')
            
            self.model = settingsModel.load_from_file(DATAFILENAME)
            
            self._p(str(self.model))
        else:
            # create new model
            self._p('no existing file found, create new model')
            self.model = settingsModel()
            self.model.store_to_file(DATAFILENAME)
        
        # parse command line arguments, hanlde help display, ...
        parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter, description='This Program provides easy to use switching the current screenlayout with xrandr/arandr with saved configurations.')
        # check if modes where defined
        if len(self.model.modes()) > 0:
            parser.add_argument('mode', type=int, metavar='screenMode', help='selected screenmode, supported screnmodes are:\n{0}'.format(self.model.toHelpString()))
        else:
            parser.add_argument('mode', type=int, metavar='screenMode', help='selected screenmode')
        parser.add_argument('-a', '--add', nargs=2, help='create new screenlayout and add it to datamodel', metavar=('filename', 'description'))
        parser.add_argument('-ca', '--call_arandr', action='store_true', help='call arandr while adding a new screenlayout')
        parser.add_argument('-r', '--remove', action='store_true', help='remove existing layout and delete defined configuration file')
        parser.add_argument('-kf', '--keep_file', action='store_true', help='keep the configuration file while removing configuration entry')
        parser.add_argument('-c', '--apply_current', action='store_true', help='ignore chosen mode and apply current configuration')
        parser.add_argument('-v', '--verbosity', action='store_true', help='enable detailed output')
        args = parser.parse_args()
        
        # execute command according to cmd line parameters
        
        # check add parameter
        if args.add:
            self.add_layout(args.add[0], args.add[1], args.mode, args.call_arandr)
        elif args.remove:
            self.remove_layout(args.mode, not args.keep_file)
        elif args.apply_current:
            self.apply_current()
        else:
            self.apply_layout(args.mode)
        
        self._p('finished')
        
if __name__=='__main__':
    app = application('-v' in sys.argv or '--verbosity' in sys.argv)
    app.main()
    '''    
    model = settingsModel()
    model.add('file0', 'desc0')
    model.add('file1', 'desc1')
    model.add('file2', 'desc2')
    model.store_to_file(DATAFILENAME)
    '''
